package org.longsheng.GroovyLearn.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashSet;

/**
 * JAVA基础
 */
@RestController
@RequestMapping("/base")
public class JavaBaseController {

    @RequestMapping("/hashcode")
    public String hashCodeTest() {
        EqualExample e1 = new EqualExample(1, 1, 1);
        EqualExample e2 = new EqualExample(1, 1, 1);
        System.out.println(e1.equals(e2)); // true

        HashSet<EqualExample> set = new HashSet<>();
        set.add(e1);
        set.add(e2);
        System.out.println(set.size());

        return e1.equals(e2) + " - " + set.size();
    }

    @RequestMapping("/interface")
    public String interfaceTest() {
        String result = "interface";

        InterfaceExample ie2 = new InterfaceImplementExample();
        ie2.func1();
        System.out.println(InterfaceExample.x);
        System.out.println(InterfaceExample.z);

        return result;
    }

    @RequestMapping("/super")
    public String superTest() {
        SuperExample e = new SuperExtendExample(1, 2, 3);
        e.func();

        return "super";
    }
}

/**
 * 访问父类的构造函数：可以使用 super() 函数访问父类的构造函数，从而委托父类完成一些初始化的工作。应该注意到，子类一定会调用父类的构造函数来完成初始化工作，一般是调用父类的默认构造函数，如果子类需要调用父类其它构造函数，那么就可以使用 super() 函数。
 * 访问父类的成员：如果子类重写了父类的某个方法，可以通过使用 super 关键字来引用父类的方法实现。
 */
class SuperExample {
    protected int x;
    protected int y;

    public SuperExample(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void func() {
        System.out.println("SuperExample.func()");
    }
}

class SuperExtendExample extends SuperExample {

    private int z;

    public SuperExtendExample(int x, int y, int z) {
        super(x, y);
        this.z = z;
    }

    @Override
    public void func() {
        super.func();
        System.out.println("SuperExtendExample.func()");
    }
}

/**
 * 抽象类和抽象方法都使用 abstract 关键字进行声明。如果一个类中包含抽象方法，那么这个类必须声明为抽象类。
 *
 * 抽象类和普通类最大的区别是，抽象类不能被实例化，只能被继承。
 */
abstract class AbstractClassExample {
    protected int x;
    protected int y;

    public abstract void func1();

    public void func2() {
        System.out.println("func2");
    }
}

class AbstractExtendClassExample extends AbstractClassExample {

    @Override
    public void func1() {
        System.out.println("func1");
    }
}

/**
 * 接口是抽象类的延伸，在 Java 8 之前，它可以看成是一个完全抽象的类，也就是说它不能有任何的方法实现。
 *
 * 从 Java 8 开始，接口也可以拥有默认的方法实现，这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前，如果一个接口想要添加新的方法，那么要修改所有实现了该接口的类，让它们都实现新增的方法。
 *
 * 接口的成员（字段 + 方法）默认都是 public 的，并且不允许定义为 private 或者 protected。从 Java 9 开始，允许将方法定义为 private，这样就能定义某些复用的代码又不会把方法暴露出去。
 *
 * 接口的字段默认都是 static 和 final 的。
 */
interface InterfaceExample {
    int x = 123;

    public int z = 0;

    void func1();

    default void func2() {
        System.out.println("func2");
    }
}

class InterfaceImplementExample implements InterfaceExample {

    @Override
    public void func1() {
        System.out.println("func1");
    }
}

/**
 * 等价与相等
 *
 * 实现 *
 * 检查是否为同一个对象的引用，如果是直接返回 true；
 * 检查是否是同一个类型，如果不是，直接返回 false；
 * 将 Object 对象进行转型；
 * 判断每个关键域是否相等。
 */
class EqualExample {
    private int x;
    private int y;
    private int z;

    public EqualExample(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EqualExample that = (EqualExample) o;

        if (x != that.x) return false;
        if (y != this.y) return false;

        return z == that.z;
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + x;
        result = 31 * result + y;
        result = 31 * result + z;

        return result;
    }
}

/**
 * 但是在方法中将指针引用了其它对象，那么此时方法里和方法外的两个指针指向了不同的对象，在一个指针改变其所指向对象的内容对另一个指针所指向的对象没有影响。
 */
class PassByValueExample2 {
    public static void main(String[] args) {
        Dog dog = new Dog("A");
        System.out.println(dog.getObjectAddress()); // Dog@4554617c

        func(dog);
        System.out.println(dog.getObjectAddress()); // Dog@4554617c
        System.out.println(dog.getName()); // A
    }

    private static void func(Dog dog) {
        System.out.println(dog.getObjectAddress()); // Dog@4554617c

        dog = new Dog("B");
        System.out.println(dog.getObjectAddress()); // Dog@74a14482
        System.out.println(dog.getName()); // B
    }
}

/**
 * 在方法中改变对象的字段值会改变原对象该字段值，因为引用的是同一个对象。
 */
class PassByValueExample {
    public static void main(String[] args) {
        Dog dog = new Dog("A");
        func(dog);

        System.out.println(dog.getName()); // B
    }

    private static void func(Dog dog) {
        dog.setName("B");
    }
}

/**
 * 以下代码中 Dog dog 的 dog 是一个指针，存储的是对象的地址。在将一个参数传入一个方法时，本质上是将对象的地址以值的方式传递到形参中。
 */
class Dog {
    String name;

    Dog(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    String getObjectAddress() {
        return super.toString();
    }
}

/**
 * 在 Java 8 中，String 内部使用 char 数组存储数据
 */
final class String8
        implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    public String8(char[] value) {
        this.value = value;
    }

    @Override
    public int length() {
        return 0;
    }

    @Override
    public char charAt(int index) {
        return 0;
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        return null;
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }
}

/**
 * 在 Java 9 之后，String 类的实现改用 byte 数组存储字符串，同时使用 coder 来标识使用了哪种编码。
 */
final class String9
        implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final byte[] value;

    /** The identifier of the encoding used to encode the bytes in {@code value}. */
    private final byte coder;

    public String9(byte[] value, byte coder) {
        this.value = value;
        this.coder = coder;
    }

    @Override
    public int length() {
        return 0;
    }

    @Override
    public char charAt(int index) {
        return 0;
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        return null;
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }
}
